package SGLisp

import (
	"fmt"

	. "git.oschina.net/yangdao/SGLisp/parse"
	//. "git.oschina.net/yangdao/extlib"
	//. "git.oschina.net/yangdao/extlib/data_type"
)

var StaticNilNode NilNode

func defineCoreFunctions() {
	MainContext.DefineFunc("do", _do)
	MainContext.DefineFunc("def", _def)
	MainContext.DefineFunc("repeat", _repeat)
	MainContext.DefineFunc("vector-s", _vector_s)
	MainContext.DefineFunc("=", _equal)
	MainContext.DefineFunc("fn", _fn)
	MainContext.DefineFunc("log", _log)
	MainContext.DefineFunc("filter", _filter)
	MainContext.DefineFunc(">", _gt)
	MainContext.DefineFunc("<", _lt)
	MainContext.DefineFunc("hash-map", Hash_map)
	MainContext.DefineFunc("apply", _apply)
	MainContext.DefineFunc("map", _map)
	MainContext.DefineFunc("-", _sub)
	MainContext.DefineFunc("*", _mult)
	MainContext.DefineFunc("int", _int)
	MainContext.DefineFunc("and", _and)
	MainContext.DefineFunc("if", _if)
	MainContext.DefineFunc("if-let", _if_let)
}

func EvalArgs(args []Node, context *Context) []Node {
	newargs := make([]Node, len(args))
	for i := 0; i < len(args); i++ {
		newargs[i] = Evaluate(args[i], context)
	}
	return newargs
}

func _if_let(args []Node, context *Context) Node {
	letVec := args[0].(*VectorNode)
	letVecValue := Evaluate(letVec.Children()[1], context)
	if letVecValue == nil || letVecValue.Type() == NodeType_NilNode {
		if len(args) > 2 {
			return Evaluate(args[2], context)
		}
		return nil
	}
	newContext := NewContext(context)
	newContext.Define(letVec.Children()[0].(*SymbolNode).Val, letVecValue)
	Evaluate(args[1], newContext)
	return nil
}
func _if(args []Node, context *Context) Node {
	args[0] = Evaluate(args[0], context)
	if args[0].(*BoolNode).Val == true {
		Evaluate(args[1], context)
	} else if len(args) > 2 {
		Evaluate(args[2], context)
	}
	return nil
}
func _and(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	for i := 0; i < len(args); i++ {
		bNode := args[i].(*BoolNode)
		if bNode.Val == false {
			return &BoolNode{Val: false}
		}
	}
	return &BoolNode{Val: true}
}

func Hash_map(args []Node, context *Context) Node {
	retMapNode := &MapNode{Val: make(map[interface{}]interface{})}
	for i := 0; i < len(args); i += 2 {
		retMapNode.Val[args[i].HashCode()] = args[i+1]
	}
	return retMapNode
}

func _gt(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	lefNum := args[0].(*NumberNode)
	rightNum := args[1].(*NumberNode)

	switch lefNum.Val.(type) {
	case int:
		switch rightNum.Val.(type) {
		case int:
			return &BoolNode{Val: lefNum.Val.(int) > rightNum.Val.(int)}
		}
	}

	return nil
}

func _lt(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	lefNum := args[0].(*NumberNode)
	rightNum := args[1].(*NumberNode)

	switch lefNum.Val.(type) {
	case int:
		switch rightNum.Val.(type) {
		case int:
			return &BoolNode{Val: lefNum.Val.(int) < rightNum.Val.(int)}
		}
	}
	return nil
}

func _log(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	arg0 := args[0]
	switch arg0.(type) {
	case *StringNode:
		fmt.Println(arg0.(*StringNode).Val)
	case *NumberNode:
		fmt.Println(arg0.(*NumberNode).Val)
	default:
		fmt.Println(arg0)
	}
	return nil
}

func _equal(args []Node, context *Context) Node {
	retBoolNode := &BoolNode{Val: false}
	args = EvalArgs(args, context)
	switch args[0].(type) {
	case *BoolNode:

		v0 := args[0].(*BoolNode)
		v1 := args[1].(*BoolNode)

		if v0.Val == v1.Val {
			retBoolNode.Val = true
		}
	case *ObjectNode:
		v0 := args[0].(*ObjectNode)
		v1 := args[1].(*ObjectNode)
		if v0.Val == v1.Val {
			retBoolNode.Val = true
		}
	case *NumberNode:
		v0 := args[0].(*NumberNode)
		v1 := args[1].(*NumberNode)
		if v0.Val == v1.Val {
			retBoolNode.Val = true
		}
	case *StringNode:
		if args[0].(*StringNode).Val == args[1].(*StringNode).Val {
			retBoolNode.Val = true
		}
	}
	return retBoolNode
}

func _do(args []Node, context *Context) Node {
	for i := 0; i < len(args)-1; i++ {
		Evaluate(args[i], context)
	}

	return Evaluate(args[len(args)-1], context)
}

func _def(args []Node, context *Context) Node {
	args[1] = Evaluate(args[1], context)
	symNode := args[0].(*SymbolNode)
	context.Define(symNode.Val, args[1])
	return nil
}

func _repeat(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	repeatNumber := args[0].(*NumberNode).Val.(int)
	retVecNode := &VectorNode{}
	//retVecNode.Nodes
	for i := 0; i < repeatNumber; i++ {
		//TODO
	}
	return retVecNode
}

func _vector_s(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	retVecNode := VectorNode{}
	sizei := args[0].(*NumberNode).Val.(int)
	retVecNode.Nodes = make([]Node, sizei)
	for i := 0; i < sizei; i++ {
		retVecNode.Nodes[i] = args[1]
	}
	return retVecNode
}

func _fn(args []Node, context *Context) Node {
	argNode := args[0].(*VectorNode)
	FnNode := &FunctionNode{}
	doNode := &ListNode{}
	doNode.Nodes = append(doNode.Nodes, &SymbolNode{Val: "do"})
	for i := 0; i < len(args); i++ {
		doNode.Nodes = append(doNode.Nodes, args[i])
	}
	FnNode.ListNode = doNode
	FnNode.VecArgsNode = argNode
	return FnNode
}

func _filter(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	dataNode := args[1]
	fnNode := args[0]
	switch dataNode.(type) {
	case *VectorNode:
		vecNode := dataNode.(*VectorNode)
		newVecNode := &VectorNode{}
		for i := 0; i < len(vecNode.Nodes); i++ {
			bNode := ExecFunc(fnNode, []Node{vecNode.Nodes[i]}, context)
			if bNode.(*BoolNode).Val {
				newVecNode.Nodes = append(newVecNode.Nodes, vecNode.Nodes[i])
			}
		}
		return newVecNode
	case *QuoteNode:
		curDataNode := dataNode.(*QuoteNode)
		quoteNode := &QuoteNode{Node: &ListNode{}}
		for i := 0; i < len(curDataNode.Node.Children()); i++ {
			bNode := ExecFunc(fnNode, []Node{curDataNode.Node.Children()[i]}, context)
			if bNode.(*BoolNode).Val {

				quoteNode.Node.(*ListNode).Nodes = append(quoteNode.Node.(*ListNode).Nodes, curDataNode.Node.Children()[i])
			}
		}
		return quoteNode
	}
	return nil
}

func _apply(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	return nil
}

func _map(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	curFn := args[0]
	vecNode := args[1].(*VectorNode)
	for i := 0; i < len(vecNode.Nodes); i++ {
		ExecFunc(curFn, []Node{vecNode.Nodes[i]}, context)
	}
	return nil
}

func _sub(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	retNumberNode := &NumberNode{}
	retNumberNode.Val = args[0].(*NumberNode).Val
	argi := 0
	argi++
	for argi < len(args) {
		numNode := args[argi].(*NumberNode)
		switch numNode.Val.(type) {
		case int:
			switch numNode.Val.(type) {
			case int:
				retNumberNode.Val = retNumberNode.Val.(int) - numNode.Val.(int)
			case float64:
			}
		case float64:
		}
		argi++
	}
	return retNumberNode
}

func _mult(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	retNumberNode := &NumberNode{}
	retNumberNode.Val = args[0].(*NumberNode).Val
	argi := 0
	argi++
	for argi < len(args) {
		numNode := args[argi].(*NumberNode)
		switch retNumberNode.Val.(type) {
		case int:
			switch numNode.Val.(type) {
			case int:
				retNumberNode.Val = retNumberNode.Val.(int) * numNode.Val.(int)
			case float64:
				retNumberNode.Val = float64(retNumberNode.Val.(int)) * numNode.Val.(float64)
			}
		}
		argi++
	}
	return retNumberNode
}

func _int(args []Node, context *Context) Node {
	args = EvalArgs(args, context)
	NumVal := args[0].(*NumberNode)
	switch NumVal.Val.(type) {
	case float64:
		return &NumberNode{Val: int(NumVal.Val.(float64))}
	case float32:
		return &NumberNode{Val: int(NumVal.Val.(float32))}
	}
	return nil
}
